#pragma once
#include <BWAPI.h>
#include "UnitGroup.h"
#include "MineAction.h"
#include "TrainAction.h"
#include "BuildAction.h"
#include "VZManager.h"

struct LeadTime
{
	int first;
	int last;
};

typedef struct {
	UnitType uType;
	UnitGroup *group;
	int count;
	int priority;
	TilePosition position;
} Request;

class StratManager;

class BasicManager
{
	bool enabled;
protected:
	StratManager *manager;// Strat manager.

	virtual struct LeadTime getUnitRequestTime(Request unitRequest)=0;
	virtual void onStart()=0;
	virtual void onThink()=0;
	virtual void onStop()=0;
	virtual void onUnitRecieved(Unit *unit, bool requested=false)=0;

	struct LeadTime unitsLeadTime(Request request); // will return expected frames until units are ready
	void requestUnits(Request unitRequest); // make the actual request to manager for units;
public:
	virtual bool canTransferUnits(Request unitRequest)=0;
	virtual bool canTrainUnits()=0;
	void giveUnit(Unit *unit, bool requested) { onUnitRecieved(unit,requested); }
	void start();
	void think();
	void stop();
	void addArrival(struct arrival arrival);
	virtual void onTaskCompleted(UnitGroup* group)=0;
};

class NonCombatUnitManager : public BasicManager
{
	friend class UnitGroup;
	struct LeadTime getUnitRequestTime(Request unitRequest);
	void onStart();
	void onStop();
	void onThink();
	void onUnitRecieved(Unit *unit, bool requested=false);
	UnitGroup *miners;
	bool minerRequestSent;
	bool supplyRequestSent;
	int minersLeft;
public:
	void buildUnits(Request unitRequest);
	void onTaskCompleted(UnitGroup* group);
	NonCombatUnitManager(StratManager *newManager);
	bool canTransferUnits(Request unitRequest);
	bool canTrainUnits() { return false; }
	~NonCombatUnitManager();
};

class TrainingManager : public BasicManager
{
	friend class UnitGroup;
	UnitGroup *centers;
	bool supplyRequestSent;
	int suppliesLeft;

	void onStart();
	void onStop();
	void onThink();
	struct LeadTime getUnitRequestTime(Request unitRequest);
	void onUnitRecieved(Unit *unit, bool requested=false);
public:
	void onTaskCompleted(UnitGroup* group);
	TrainingManager(StratManager *newManager);
	bool canTransferUnits(Request unitRequest) { return false; }
	bool canTrainUnits() { return true; } // currently always true but will eventally look at work load
	void trainUnits(Request unitRequest);
	~TrainingManager();
};

class StratManager
{
	static priority_queue<struct arrival, vector<struct arrival>, ArrivalCompare> arrivalQueue;

	// declare all the managers here
	NonCombatUnitManager *NCUManager;
	TrainingManager *trainingManager;
	VZManager vzManager;
public:
	// Descide whether to train units transfer units or both.
	StratManager();
	void onUnitRequest(Request request);
	struct LeadTime onUnitTimeQuerry(Request request);
	void onStart();
	void onThink();
	void vzThink();
	void onStop();
	void onUnitArrival(Unit *unit);
	void onUnitDiscover(Unit *unit);
	void addArrival(struct arrival);
	~StratManager();
};